/*******************************************************************************
 *    版权信息   ： @copyright Copyright 2014-2021 chnenergy All Right Reserved
 *    作   者   ： hhz
 *    版   本   ： 1.1
 *    创建时间   ：2024/4/11
 *    最后修改日期   ： 2024/4/11
 *    最后修改人员   ： hhz
 ******************************************************************************/
package cn.neo.hhrpc.core.cluster;

import cn.neo.hhrpc.core.api.Router;
import cn.neo.hhrpc.core.meta.InstanceMeta;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 灰度路由
 *  灰度节点部署就是为了验证的，所以需要灰度路由
 *  全链路灰度可以做一些灰度用户或某一次请求上加灰度标记。比如在请求头上加上标识，如果上下文中被灰度染色，直接返回
 */

@Slf4j
@Setter
public class GrayRouter implements Router<InstanceMeta> {


    private int grayRatio;

    private final Random random = new Random();

    public GrayRouter(int grayRatio) {
        this.grayRatio = grayRatio;
    }

    @Override
    public List<InstanceMeta> route(List<InstanceMeta> providers) {

        // ctx.gray=true

        if (CollectionUtils.isEmpty(providers)) return providers;

        // 对标记的 provider 进行分类
        List<InstanceMeta> normalNodes = new ArrayList<>();
        List<InstanceMeta> grayNodes = new ArrayList<>();

        providers.forEach(provider -> {
            if ("true".equals(provider.getParameters().get("gray"))) {
                grayNodes.add(provider);
            } else {
                normalNodes.add(provider);
            }
        });

        log.debug(" grayRouter grayNodes/normalNodes,grayRatio ===> {}/{},{}",
                grayNodes.size(), normalNodes.size(), grayRatio);

        if (normalNodes.isEmpty() || grayNodes.isEmpty()) return providers;

        if (grayRatio <= 0) {
            return normalNodes;
        } else if (grayRatio >= 100) {
            return grayNodes;
        }

        // 情况 1(不合适)：类似虚拟节点。需要一个大集合。包含 gray 和 normal nodes。同时通过grayRatio 算好。但是前提得假设 LB 一定是线性的均匀分布
        // 情况 2(合适)：随机数。在 A 的情况下返回 normal，在 B 的情况下返回 gray nodes
        if(random.nextInt(100) < grayRatio) {
            log.debug(" grayRouter grayNodes ===> {}", grayNodes);
            return grayNodes;
        } else {
            log.debug(" grayRouter normalNodes ===> {}", normalNodes);
            return normalNodes;
        }

    }
}
